Fix problems with direct-mapping handling especially when
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 16 Feb 2006 15:46:21 +0000 (16:46 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 16 Feb 2006 15:46:21 +0000 (16:46 +0100)
VMX assist is used for real mode and protected mode.

Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
Signed-off-by: Xin B Li <xin.b.li@intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/shadow.c
xen/arch/x86/shadow32.c
xen/arch/x86/shadow_public.c
xen/include/asm-x86/shadow.h
xen/include/asm-x86/shadow_64.h

index 14f04bd0a80a919a8c4dbcf742259eb992a2ac2b..4aa3b89be32c68eeea2725086c78872aef67a4c5 100644 (file)
@@ -799,6 +799,7 @@ void svm_relinquish_resources(struct vcpu *v)
         struct domain *d = v->domain;
         if (d->arch.hvm_domain.shared_page_va)
             unmap_domain_page((void *)d->arch.hvm_domain.shared_page_va);
+        shadow_direct_map_clean(v);
     }
 
     destroy_vmcb(&v->arch.hvm_svm);
@@ -1443,9 +1444,7 @@ static int svm_set_cr0(unsigned long value)
                 put_page(mfn_to_page(old_base_mfn));
        }
 #endif
-#if CONFIG_PAGING_LEVELS == 2
-        shadow_direct_map_clean(v);
-#endif
+
         /* Now arch.guest_table points to machine physical. */
         v->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT);
         update_pagetables(v);
index 67e6f21835cfeb3774c6bc66cbf6052c47fb627a..c9f3171aa73ac85595de39035c65e04856c635c7 100644 (file)
@@ -88,6 +88,7 @@ void vmx_relinquish_resources(struct vcpu *v)
         if ( d->arch.hvm_domain.shared_page_va )
             unmap_domain_page_global(
                (void *)d->arch.hvm_domain.shared_page_va);
+        shadow_direct_map_clean(v);
     }
 
     vmx_request_clear_vmcs(v);
@@ -1227,9 +1228,7 @@ static int vmx_set_cr0(unsigned long value)
                 __vmwrite(GUEST_CR4, crn | X86_CR4_PAE);
             }
         }
-#if CONFIG_PAGING_LEVELS == 2
-        shadow_direct_map_clean(v);
-#endif
+
         /*
          * Now arch.guest_table points to machine physical.
          */
index f9bffa40c707b3fb5c8797042898d54f9a7588ed..2a2ae5cdbeeff8bbe6463dceb287b30604acd027 100644 (file)
@@ -3743,6 +3743,7 @@ struct shadow_ops MODE_32_2_HANDLER = {
 #if ( CONFIG_PAGING_LEVELS == 3 && !defined (GUEST_PGENTRY_32) ) ||  \
     ( CONFIG_PAGING_LEVELS == 4 && defined (GUEST_PGENTRY_32) )
 
+
 /* 
  * Use GUEST_PGENTRY_32 to force PAE_SHADOW_SELF_ENTRY for L4.
  *
@@ -3756,8 +3757,8 @@ int shadow_direct_map_fault(unsigned long vpa, struct cpu_user_regs *regs)
 {
     struct vcpu *v = current;
     struct domain *d = v->domain;
-    l3_pgentry_t sl3e;
-    l2_pgentry_t sl2e;
+    l3_pgentry_t sl3e, *sl3e_p;
+    l2_pgentry_t sl2e, *sl2e_p;
     l1_pgentry_t sl1e;
     unsigned long mfn, smfn;
     struct page_info *page;
@@ -3773,37 +3774,47 @@ int shadow_direct_map_fault(unsigned long vpa, struct cpu_user_regs *regs)
 
     shadow_lock(d);
 
-    __shadow_get_l3e(v, vpa, &sl3e);
+    __direct_get_l3e(v, vpa, &sl3e);
 
     if ( !(l3e_get_flags(sl3e) & _PAGE_PRESENT) ) 
     {
         page = alloc_domheap_page(NULL);
         if ( !page )
-            goto fail; 
+            goto nomem; 
+
         smfn = page_to_mfn(page);
         sl3e = l3e_from_pfn(smfn, _PAGE_PRESENT);
-        __shadow_set_l3e(v, vpa, &sl3e);
+
+        sl3e_p = (l3_pgentry_t *)map_domain_page(smfn);
+        memset(sl3e_p, 0, PAGE_SIZE);
+        unmap_domain_page(sl3e_p);
+
+        __direct_set_l3e(v, vpa, &sl3e);
     }
 
-    __shadow_get_l2e(v, vpa, &sl2e);
+    __direct_get_l2e(v, vpa, &sl2e);
 
     if ( !(l2e_get_flags(sl2e) & _PAGE_PRESENT) ) 
     {
         page = alloc_domheap_page(NULL);
         if ( !page )
-            goto fail; 
-        smfn = page_to_mfn(page);
+            goto nomem; 
 
+        smfn = page_to_mfn(page);
         sl2e = l2e_from_pfn(smfn, __PAGE_HYPERVISOR | _PAGE_USER);
-        __shadow_set_l2e(v, vpa, &sl2e);
+        sl2e_p = (l2_pgentry_t *)map_domain_page(smfn);
+        memset(sl2e_p, 0, PAGE_SIZE);
+        unmap_domain_page(sl2e_p);
+
+        __direct_set_l2e(v, vpa, &sl2e);
     }
 
-    __shadow_get_l1e(v, vpa, &sl1e);
+    __direct_get_l1e(v, vpa, &sl1e);
 
     if ( !(l1e_get_flags(sl1e) & _PAGE_PRESENT) ) 
     {
         sl1e = l1e_from_pfn(mfn, __PAGE_HYPERVISOR | _PAGE_USER);
-        __shadow_set_l1e(v, vpa, &sl1e);
+        __direct_set_l1e(v, vpa, &sl1e);
     } 
 
     shadow_unlock(d);
@@ -3811,6 +3822,10 @@ int shadow_direct_map_fault(unsigned long vpa, struct cpu_user_regs *regs)
 
 fail:
     return 0;
+
+nomem:
+    shadow_direct_map_clean(v);
+    domain_crash_synchronous();
 }
 #endif
 
index ae1d8a036fcfeb24fecafc9ce9cf521049014fd5..cb641843ba876ac3998b0046a5a274d9be3568c9 100644 (file)
@@ -807,21 +807,99 @@ void free_monitor_pagetable(struct vcpu *v)
     v->arch.monitor_vtable = 0;
 }
 
+static int
+map_p2m_entry(
+    l1_pgentry_t *l1tab, unsigned long va, unsigned long gpa, unsigned long mfn)
+{
+    unsigned long *l0tab = NULL;
+    l1_pgentry_t l1e = { 0 };
+    struct page_info *page;
+
+    l1e = l1tab[l1_table_offset(va)];
+    if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) )
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto fail;
+
+        if ( l0tab  )
+            unmap_domain_page(l0tab);
+        l0tab = map_domain_page(page_to_mfn(page));
+        memset(l0tab, 0, PAGE_SIZE );
+        l1e = l1tab[l1_table_offset(va)] =
+            l1e_from_page(page, __PAGE_HYPERVISOR);
+    }
+    else if ( l0tab == NULL)
+        l0tab = map_domain_page(l1e_get_pfn(l1e));
+
+    l0tab[gpa & ((PAGE_SIZE / sizeof (mfn)) - 1) ] = mfn;
+
+    if ( l0tab )
+        unmap_domain_page(l0tab);
+
+    return 1;
+
+fail:
+    return 0;
+}
+
 int
 set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn,
               struct domain_mmap_cache *l2cache,
               struct domain_mmap_cache *l1cache)
 {
-    unsigned long tabpfn = pagetable_get_pfn(d->arch.phys_table);
+    unsigned long tabpfn;
     l2_pgentry_t *l2, l2e;
     l1_pgentry_t *l1;
     struct page_info *l1page;
     unsigned long va = pfn << PAGE_SHIFT;
+    int error;
+
+    if ( shadow_mode_external(d) )
+    {
+        tabpfn = pagetable_get_pfn(d->vcpu[0]->arch.monitor_table);
+        va = RO_MPT_VIRT_START + (pfn * sizeof (unsigned long));
+    }
+    else
+    {
+        tabpfn = pagetable_get_pfn(d->arch.phys_table);
+        va = pfn << PAGE_SHIFT;
+    }
 
     ASSERT(tabpfn != 0);
     ASSERT(shadow_lock_is_acquired(d));
 
     l2 = map_domain_page_with_cache(tabpfn, l2cache);
+
+    /*
+     * The following code covers (SHM_translate | SHM_external) mode.
+     */
+
+    if ( shadow_mode_external(d) )
+    {
+        l1_pgentry_t *l1tab = NULL;
+        l2_pgentry_t l2e;
+
+        l2e = l2[l2_table_offset(va)];
+
+        ASSERT( l2e_get_flags(l2e) & _PAGE_PRESENT );
+
+        l1tab = map_domain_page(l2e_get_pfn(l2e));
+        error = map_p2m_entry(l1tab, va, pfn, mfn);
+        if ( !error )
+            domain_crash_synchronous(); 
+
+        unmap_domain_page(l1tab);
+        unmap_domain_page_with_cache(l2, l2cache);
+
+        return 1;
+    }
+
+    /*
+     * The following code covers SHM_translate mode.
+     */
+    ASSERT(shadow_mode_translate(d));
+
     l2e = l2[l2_table_offset(va)];
     if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
     {
@@ -856,13 +934,10 @@ alloc_p2m_table(struct domain *d)
 
     l2_pgentry_t *l2tab = NULL;
     l1_pgentry_t *l1tab = NULL;
-    unsigned long *l0tab = NULL;
     l2_pgentry_t l2e = { 0 };
-    l1_pgentry_t l1e = { 0 };
-
     struct page_info *page;
-    unsigned long pfn;
-    int i;
+    unsigned long gpfn, mfn;
+    int error;
 
     if ( pagetable_get_pfn(d->vcpu[0]->arch.monitor_table) )
     {
@@ -892,34 +967,22 @@ alloc_p2m_table(struct domain *d)
 
     list_ent = d->page_list.next;
 
-    for ( i = 0; list_ent != &d->page_list; i++ )
+    for ( gpfn = 0; list_ent != &d->page_list; gpfn++ )
     {
         page = list_entry(list_ent, struct page_info, list);
-        pfn = page_to_mfn(page);
+        mfn = page_to_mfn(page);
 
-        l1e = l1tab[l1_table_offset(va)];
-        if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) )
-        {
-            page = alloc_domheap_page(NULL);
-            if ( l0tab  )
-                unmap_domain_page(l0tab);
-            l0tab = map_domain_page(page_to_mfn(page));
-            memset(l0tab, 0, PAGE_SIZE );
-            l1e = l1tab[l1_table_offset(va)] =
-                l1e_from_page(page, __PAGE_HYPERVISOR);
-        }
-        else if ( l0tab == NULL)
-            l0tab = map_domain_page(l1e_get_pfn(l1e));
+        error = map_p2m_entry(l1tab, va, gpfn, mfn);
+        if ( !error )
+            domain_crash_synchronous(); 
 
-        l0tab[i & ((1 << PAGETABLE_ORDER) - 1) ] = pfn;
-        list_ent = frame_table[pfn].list.next;
-        va += sizeof(pfn);
+        list_ent = frame_table[mfn].list.next;
+        va += sizeof(mfn);
     }
 
     if (l2tab)
         unmap_domain_page(l2tab);
     unmap_domain_page(l1tab);
-    unmap_domain_page(l0tab);
 
     return 1;
 }
@@ -981,21 +1044,26 @@ int shadow_direct_map_fault(unsigned long vpa, struct cpu_user_regs *regs)
     }
 
     shadow_lock(d);
+  
+   __direct_get_l2e(v, vpa, &sl2e);
 
-    __shadow_get_l2e(v, vpa, &sl2e);
-
-   if ( !(l2e_get_flags(sl2e) & _PAGE_PRESENT) )
+    if ( !(l2e_get_flags(sl2e) & _PAGE_PRESENT) )
     {
         page = alloc_domheap_page(NULL);
         if ( !page )
-            goto fail;
+            goto nomem;
 
         smfn = page_to_mfn(page);
         sl2e = l2e_from_pfn(smfn, __PAGE_HYPERVISOR | _PAGE_USER);
-        __shadow_set_l2e(v, vpa, sl2e);
-    }
 
-    sple = (l1_pgentry_t *)map_domain_page(l2e_get_pfn(sl2e));
+        sple = (l1_pgentry_t *)map_domain_page(smfn);
+        memset(sple, 0, PAGE_SIZE);
+        __direct_set_l2e(v, vpa, sl2e);
+    } 
+
+    if ( !sple )
+        sple = (l1_pgentry_t *)map_domain_page(l2e_get_pfn(sl2e));
+
     sl1e = sple[l1_table_offset(vpa)];
 
     if ( !(l1e_get_flags(sl1e) & _PAGE_PRESENT) )
@@ -1003,13 +1071,19 @@ int shadow_direct_map_fault(unsigned long vpa, struct cpu_user_regs *regs)
         sl1e = l1e_from_pfn(mfn, __PAGE_HYPERVISOR | _PAGE_USER);
         sple[l1_table_offset(vpa)] = sl1e;
     }
-    unmap_domain_page(sple);
-    shadow_unlock(d);
 
+    if (sple)
+        unmap_domain_page(sple);
+
+    shadow_unlock(d);
     return EXCRET_fault_fixed;
 
 fail:
     return 0;
+
+nomem:
+    shadow_direct_map_clean(v);
+    domain_crash_synchronous();
 }
 
 
@@ -1021,16 +1095,12 @@ int shadow_direct_map_init(struct vcpu *v)
     if ( !(page = alloc_domheap_page(NULL)) )
         goto fail;
 
-    root = map_domain_page_global(page_to_mfn(page));
+    root = map_domain_page(page_to_mfn(page));
     memset(root, 0, PAGE_SIZE);
+    unmap_domain_page(root);
 
     v->domain->arch.phys_table = mk_pagetable(page_to_maddr(page));
-    /* 
-     * We need to set shadow_vtable to get __shadow_set/get_xxx
-     * working
-     */
-    v->arch.shadow_vtable = (l2_pgentry_t *) root;
-    v->arch.shadow_table = mk_pagetable(0);
+
     return 1;
 
 fail:
@@ -1042,9 +1112,8 @@ void shadow_direct_map_clean(struct vcpu *v)
     int i;
     l2_pgentry_t *l2e;
 
-    ASSERT ( v->arch.shadow_vtable );
-
-    l2e = v->arch.shadow_vtable;
+    l2e = map_domain_page(
+      pagetable_get_pfn(v->domain->arch.phys_table));
 
     for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ )
     {
@@ -1055,8 +1124,7 @@ void shadow_direct_map_clean(struct vcpu *v)
     free_domheap_page(
             mfn_to_page(pagetable_get_pfn(v->domain->arch.phys_table)));
 
-    unmap_domain_page_global(v->arch.shadow_vtable);
-    v->arch.shadow_vtable = 0;
+    unmap_domain_page(l2e);
     v->domain->arch.phys_table = mk_pagetable(0);
 }
 
@@ -1169,13 +1237,6 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode)
                 goto nomem;
             }
         }
-        else
-        {
-            // external guests provide their own memory for their P2M maps.
-            //
-            ASSERT(d == page_get_owner(mfn_to_page(pagetable_get_pfn(
-                d->arch.phys_table))));
-        }
     }
 
     // Get rid of any shadow pages from any previous shadow mode.
index 1a1fb9f883cbb17cd787ae4649be06b1dc3fe69a..791046d9427f0edf849a0720b77ae881a67baf26 100644 (file)
@@ -44,33 +44,28 @@ int shadow_direct_map_init(struct vcpu *v)
     if ( !(page = alloc_domheap_pages(NULL, 0, ALLOC_DOM_DMA)) )
         goto fail;
 
-    root = map_domain_page_global(page_to_mfn(page));
+    root = map_domain_page(page_to_mfn(page));
     memset(root, 0, PAGE_SIZE);
     root[PAE_SHADOW_SELF_ENTRY] = l3e_from_page(page, __PAGE_HYPERVISOR);
 
     v->domain->arch.phys_table = mk_pagetable(page_to_maddr(page));
-    /* 
-     * We need to set shadow_vtable to get __shadow_set/get_xxx
-     * working
-     */
-    v->arch.shadow_vtable = (l2_pgentry_t *) root;
 
+    unmap_domain_page(root);
     return 1;
-    
+
 fail:
     return 0;
 }
 
-static void shadow_direct_map_clean(struct vcpu *v)
+void shadow_direct_map_clean(struct vcpu *v)
 {
     l2_pgentry_t *l2e;
     l3_pgentry_t *l3e;
     int i, j;
 
-    ASSERT ( v->arch.shadow_vtable );
+    l3e = (l3_pgentry_t *)map_domain_page(
+        pagetable_get_pfn(v->domain->arch.phys_table));
 
-    l3e = (l3_pgentry_t *) v->arch.shadow_vtable;
-    
     for ( i = 0; i < PAE_L3_PAGETABLE_ENTRIES; i++ )
     {
         if ( l3e_get_flags(l3e[i]) & _PAGE_PRESENT )
@@ -90,8 +85,7 @@ static void shadow_direct_map_clean(struct vcpu *v)
     free_domheap_page(
         mfn_to_page(pagetable_get_pfn(v->domain->arch.phys_table)));
 
-    unmap_domain_page_global(v->arch.shadow_vtable);
-    v->arch.shadow_vtable = 0;
+    unmap_domain_page(l3e);
     v->domain->arch.phys_table = mk_pagetable(0);
 }
 
@@ -102,13 +96,8 @@ static void shadow_direct_map_clean(struct vcpu *v)
 
 int shadow_set_guest_paging_levels(struct domain *d, int levels)
 {
-    struct vcpu *v = current;
     shadow_lock(d);
 
-    if ( shadow_mode_translate(d) && 
-         !(pagetable_get_paddr(v->domain->arch.phys_table)) )
-         shadow_direct_map_clean(v);
-
     switch(levels) {
 #if CONFIG_PAGING_LEVELS == 4
     case 4:
@@ -1330,44 +1319,134 @@ int _shadow_mode_refcounts(struct domain *d)
     return shadow_mode_refcounts(d);
 }
 
-int
-set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn,
-              struct domain_mmap_cache *l2cache,
-              struct domain_mmap_cache *l1cache)
+static int
+map_p2m_entry(
+    pgentry_64_t *top_tab, unsigned long va, unsigned long gpa, unsigned long mfn)
 {
-    unsigned long tabpfn = pagetable_get_pfn(d->arch.phys_table);
-    l2_pgentry_t *l2, l2e;
-    l1_pgentry_t *l1;
-    struct page_info *l1page;
-    unsigned long va = pfn << PAGE_SHIFT;
+#if CONFIG_PAGING_LEVELS >= 4
+    pgentry_64_t l4e = { 0 };
+#endif
+#if CONFIG_PAGING_LEVELS >= 3
+    pgentry_64_t *l3tab = NULL;
+    pgentry_64_t l3e = { 0 };
+#endif
+    l2_pgentry_t *l2tab = NULL;
+    l1_pgentry_t *l1tab = NULL;
+    unsigned long *l0tab = NULL;
+    l2_pgentry_t l2e = { 0 };
+    l1_pgentry_t l1e = { 0 };
+    struct page_info *page;
 
-    ASSERT(tabpfn != 0);
+#if CONFIG_PAGING_LEVELS >= 4
+    l4e = top_tab[l4_table_offset(va)];
+    if ( !(entry_get_flags(l4e) & _PAGE_PRESENT) ) 
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto nomem;
 
-    l2 = map_domain_page_with_cache(tabpfn, l2cache);
-    l2e = l2[l2_table_offset(va)];
-    if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) )
+        l3tab = map_domain_page(page_to_mfn(page));
+        memset(l3tab, 0, PAGE_SIZE);
+        l4e = top_tab[l4_table_offset(va)] = 
+            entry_from_page(page, __PAGE_HYPERVISOR);
+    } 
+    else if ( l3tab == NULL)
+        l3tab = map_domain_page(entry_get_pfn(l4e));
+
+    l3e = l3tab[l3_table_offset(va)];
+#else
+    l3e = top_tab[l3_table_offset(va)];
+#endif
+    if ( !(entry_get_flags(l3e) & _PAGE_PRESENT) ) 
     {
-        l1page = alloc_domheap_page(NULL);
-        if ( !l1page )
-        {
-            unmap_domain_page_with_cache(l2, l2cache);
-            return 0;
-        }
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto nomem;
+
+        l2tab = map_domain_page(page_to_mfn(page));
+        memset(l2tab, 0, PAGE_SIZE);
+        l3e = l3tab[l3_table_offset(va)] = 
+            entry_from_page(page, __PAGE_HYPERVISOR);
+    } 
+    else if ( l2tab == NULL) 
+        l2tab = map_domain_page(entry_get_pfn(l3e));
 
-        l1 = map_domain_page_with_cache(page_to_mfn(l1page), l1cache);
-        memset(l1, 0, PAGE_SIZE);
-        unmap_domain_page_with_cache(l1, l1cache);
+    l2e = l2tab[l2_table_offset(va)];
+    if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) 
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto nomem;
 
-        l2e = l2e_from_page(l1page, __PAGE_HYPERVISOR);
-        l2[l2_table_offset(va)] = l2e;
+        l1tab = map_domain_page(page_to_mfn(page));
+        memset(l1tab, 0, PAGE_SIZE);
+        l2e = l2tab[l2_table_offset(va)] = 
+            l2e_from_page(page, __PAGE_HYPERVISOR);
+    } 
+    else if ( l1tab == NULL) 
+        l1tab = map_domain_page(l2e_get_pfn(l2e));
+
+    l1e = l1tab[l1_table_offset(va)];
+    if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) ) 
+    {
+        page = alloc_domheap_page(NULL);
+        if ( !page )
+            goto nomem;
+
+        l0tab = map_domain_page(page_to_mfn(page));
+        memset(l0tab, 0, PAGE_SIZE);
+        l1e = l1tab[l1_table_offset(va)] = 
+            l1e_from_page(page, __PAGE_HYPERVISOR);
     }
-    unmap_domain_page_with_cache(l2, l2cache);
+    else if ( l0tab == NULL) 
+        l0tab = map_domain_page(l1e_get_pfn(l1e));
 
-    l1 = map_domain_page_with_cache(l2e_get_pfn(l2e), l1cache);
-    l1[l1_table_offset(va)] = l1e_from_pfn(mfn, __PAGE_HYPERVISOR);
-    unmap_domain_page_with_cache(l1, l1cache);
+    l0tab[gpa & ((PAGE_SIZE / sizeof (mfn)) - 1) ] = mfn;
+
+    if ( l2tab )
+    {
+        unmap_domain_page(l2tab);
+        l2tab = NULL;
+    }
+    if ( l1tab )
+    {
+        unmap_domain_page(l1tab);
+        l1tab = NULL;
+    }
+    if ( l0tab )
+    {
+        unmap_domain_page(l0tab);
+        l0tab = NULL;
+    }
 
     return 1;
+
+nomem:
+
+    return 0;
+}
+
+int
+set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn,
+              struct domain_mmap_cache *l2cache,
+              struct domain_mmap_cache *l1cache)
+{
+    unsigned long tabpfn = pagetable_get_pfn(d->vcpu[0]->arch.monitor_table);
+    pgentry_64_t *top;
+    unsigned long va = RO_MPT_VIRT_START + (pfn * sizeof (unsigned long));
+    int error;
+
+    ASSERT(tabpfn != 0);
+    ASSERT(shadow_lock_is_acquired(d));
+
+    top = map_domain_page_with_cache(tabpfn, l2cache);
+    error = map_p2m_entry(top, va, pfn, mfn);
+    unmap_domain_page_with_cache(top, l2cache);
+
+    if ( !error )
+         domain_crash_synchronous();
+        
+    return 1;
 }
 
 int
@@ -1375,119 +1454,31 @@ alloc_p2m_table(struct domain *d)
 {
     struct list_head *list_ent;
     unsigned long va = RO_MPT_VIRT_START; /*  phys_to_machine_mapping */
-
-#if CONFIG_PAGING_LEVELS >= 4
-    l4_pgentry_t *l4tab = NULL;
-    l4_pgentry_t l4e = { 0 };
-#endif
-#if CONFIG_PAGING_LEVELS >= 3
-    l3_pgentry_t *l3tab = NULL;
-    l3_pgentry_t l3e = { 0 };
-#endif
-    l2_pgentry_t *l2tab = NULL;
-    l1_pgentry_t *l1tab = NULL;
-    unsigned long *l0tab = NULL;
-    l2_pgentry_t l2e = { 0 };
-    l1_pgentry_t l1e = { 0 };
-
-    unsigned long pfn;
-    int i;
+    pgentry_64_t *top_tab = NULL;
+    unsigned long mfn;
+    int gpa;
 
     ASSERT ( pagetable_get_pfn(d->vcpu[0]->arch.monitor_table) );
 
-#if CONFIG_PAGING_LEVELS >= 4
-    l4tab = map_domain_page(
+    top_tab = map_domain_page(
         pagetable_get_pfn(d->vcpu[0]->arch.monitor_table));
-#endif
-#if CONFIG_PAGING_LEVELS >= 3
-    l3tab = map_domain_page(
-        pagetable_get_pfn(d->vcpu[0]->arch.monitor_table));
-#endif
+
 
     list_ent = d->page_list.next;
 
-    for ( i = 0; list_ent != &d->page_list; i++ ) 
+    for ( gpa = 0; list_ent != &d->page_list; gpa++ ) 
     {
         struct page_info *page;
-
         page = list_entry(list_ent, struct page_info, list);
-        pfn = page_to_mfn(page);
+        mfn = page_to_mfn(page);
 
-#if CONFIG_PAGING_LEVELS >= 4
-        l4e = l4tab[l4_table_offset(va)];
-        if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) 
-        {
-            page = alloc_domheap_page(NULL);
-            l3tab = map_domain_page(page_to_mfn(page));
-            memset(l3tab, 0, PAGE_SIZE);
-            l4e = l4tab[l4_table_offset(va)] = 
-                l4e_from_page(page, __PAGE_HYPERVISOR);
-        } 
-        else if ( l3tab == NULL)
-            l3tab = map_domain_page(l4e_get_pfn(l4e));
-#endif
-        l3e = l3tab[l3_table_offset(va)];
-        if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ) 
-        {
-            page = alloc_domheap_page(NULL);
-            l2tab = map_domain_page(page_to_mfn(page));
-            memset(l2tab, 0, PAGE_SIZE);
-            l3e = l3tab[l3_table_offset(va)] = 
-                l3e_from_page(page, __PAGE_HYPERVISOR);
-        } 
-        else if ( l2tab == NULL) 
-            l2tab = map_domain_page(l3e_get_pfn(l3e));
-
-        l2e = l2tab[l2_table_offset(va)];
-        if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) 
-        {
-            page = alloc_domheap_page(NULL);
-            l1tab = map_domain_page(page_to_mfn(page));
-            memset(l1tab, 0, PAGE_SIZE);
-            l2e = l2tab[l2_table_offset(va)] = 
-                l2e_from_page(page, __PAGE_HYPERVISOR);
-        } 
-        else if ( l1tab == NULL) 
-            l1tab = map_domain_page(l2e_get_pfn(l2e));
-
-        l1e = l1tab[l1_table_offset(va)];
-        if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) ) 
-        {
-            page = alloc_domheap_page(NULL);
-            l0tab = map_domain_page(page_to_mfn(page));
-            memset(l0tab, 0, PAGE_SIZE);
-            l1e = l1tab[l1_table_offset(va)] = 
-                l1e_from_page(page, __PAGE_HYPERVISOR);
-        }
-        else if ( l0tab == NULL) 
-            l0tab = map_domain_page(l1e_get_pfn(l1e));
+        map_p2m_entry(top_tab, va, gpa, mfn);
+        list_ent = frame_table[mfn].list.next;
+        va += sizeof(mfn);
+    }
 
-        l0tab[i & ((PAGE_SIZE / sizeof (pfn)) - 1) ] = pfn;
-        list_ent = frame_table[pfn].list.next;
-        va += sizeof (pfn);
+    unmap_domain_page(top_tab);
 
-        if ( l2tab )
-        {
-            unmap_domain_page(l2tab);
-            l2tab = NULL;
-        }
-        if ( l1tab )
-        {
-            unmap_domain_page(l1tab);
-            l1tab = NULL;
-        }
-        if ( l0tab )
-        {
-            unmap_domain_page(l0tab);
-            l0tab = NULL;
-        }
-    }
-#if CONFIG_PAGING_LEVELS >= 4
-    unmap_domain_page(l4tab);
-#endif
-#if CONFIG_PAGING_LEVELS >= 3
-    unmap_domain_page(l3tab);
-#endif
     return 1;
 }
 
index 3fff8e9be5a152138b8536279263511d4d3f0d3a..6c41b9b3f1e37cf912a8d0493b99a21fe3a43373 100644 (file)
@@ -115,9 +115,7 @@ do {                                            \
 #define SHADOW_ENCODE_MIN_MAX(_min, _max) ((((GUEST_L1_PAGETABLE_ENTRIES - 1) - (_max)) << 16) | (_min))
 #define SHADOW_MIN(_encoded) ((_encoded) & ((1u<<16) - 1))
 #define SHADOW_MAX(_encoded) ((GUEST_L1_PAGETABLE_ENTRIES - 1) - ((_encoded) >> 16))
-#if CONFIG_PAGING_LEVELS == 2
 extern void shadow_direct_map_clean(struct vcpu *v);
-#endif
 extern int shadow_direct_map_init(struct vcpu *v);
 extern int shadow_direct_map_fault(
     unsigned long vpa, struct cpu_user_regs *regs);
@@ -558,6 +556,38 @@ __guest_set_l2e(
     __mark_dirty(d, pagetable_get_pfn(v->arch.guest_table));
 }
 
+static inline void
+__direct_get_l2e(
+    struct vcpu *v, unsigned long va, l2_pgentry_t *psl2e)
+{
+    l2_pgentry_t *phys_vtable;
+
+    ASSERT(shadow_mode_enabled(v->domain));
+
+    phys_vtable = map_domain_page(
+        pagetable_get_pfn(v->domain->arch.phys_table));
+
+    *psl2e = phys_vtable[l2_table_offset(va)];
+
+    unmap_domain_page(phys_vtable);
+}
+
+static inline void
+__direct_set_l2e(
+    struct vcpu *v, unsigned long va, l2_pgentry_t value)
+{
+    l2_pgentry_t *phys_vtable;
+
+    ASSERT(shadow_mode_enabled(v->domain));
+
+    phys_vtable = map_domain_page(
+        pagetable_get_pfn(v->domain->arch.phys_table));
+
+    phys_vtable[l2_table_offset(va)] = value;
+
+    unmap_domain_page(phys_vtable);
+}
+
 static inline void
 update_hl2e(struct vcpu *v, unsigned long va)
 {
index 61bab70dd6fe9e6706bb3a28cc93a662a9459732..4d5d5cf922f75f26d0a4c0d2560d38ad1f408821 100644 (file)
@@ -66,9 +66,12 @@ typedef struct { intpte_t l4; } l4_pgentry_t;
 #define PAGING_L1      1UL
 #define L_MASK  0xff
 
+#define PAE_PAGING_LEVELS   3
+
 #define ROOT_LEVEL_64   PAGING_L4
 #define ROOT_LEVEL_32   PAGING_L2
 
+#define DIRECT_ENTRY    (4UL << 16)
 #define SHADOW_ENTRY    (2UL << 16)
 #define GUEST_ENTRY     (1UL << 16)
 
@@ -94,6 +97,7 @@ typedef struct { intpte_t lo; } pgentry_64_t;
 #define entry_empty()           ((pgentry_64_t) { 0 })
 #define entry_from_pfn(pfn, flags)  \
     ((pgentry_64_t) { ((intpte_t)(pfn) << PAGE_SHIFT) | put_pte_flags(flags) })
+#define entry_from_page(page, flags) (entry_from_pfn(page_to_mfn(page),(flags)))
 #define entry_add_flags(x, flags)    ((x).lo |= put_pte_flags(flags))
 #define entry_remove_flags(x, flags) ((x).lo &= ~put_pte_flags(flags))
 #define entry_has_changed(x,y,flags) \
@@ -162,16 +166,24 @@ static inline int __entry(
 
     if ( flag & SHADOW_ENTRY )
     {
-       root_level =  ROOT_LEVEL_64;
-       index = table_offset_64(va, root_level);
+        root_level =  ROOT_LEVEL_64;
+        index = table_offset_64(va, root_level);
         le_e = (pgentry_64_t *)&v->arch.shadow_vtable[index];
     }
-    else /* guest entry */  
+    else if ( flag & GUEST_ENTRY )
     {
         root_level = v->domain->arch.ops->guest_paging_levels;
-       index = table_offset_64(va, root_level);
+        index = table_offset_64(va, root_level);
         le_e = (pgentry_64_t *)&v->arch.guest_vtable[index];
     }
+    else /* direct mode */
+    {
+        root_level = PAE_PAGING_LEVELS;
+        index = table_offset_64(va, root_level);
+        le_e = (pgentry_64_t *)map_domain_page(
+            pagetable_get_pfn(v->domain->arch.phys_table));
+    }
+
     /*
      * If it's not external mode, then mfn should be machine physical.
      */
@@ -241,6 +253,20 @@ static inline int __rw_entry(
 #define __guest_get_l3e(v, va, sl3e) \
   __rw_entry(v, va, gl3e, GUEST_ENTRY | GET_ENTRY | PAGING_L3)
 
+#define __direct_set_l3e(v, va, value) \
+  __rw_entry(v, va, value, DIRECT_ENTRY | SET_ENTRY | PAGING_L3)
+#define __direct_get_l3e(v, va, sl3e) \
+  __rw_entry(v, va, sl3e, DIRECT_ENTRY | GET_ENTRY | PAGING_L3)
+#define __direct_set_l2e(v, va, value) \
+  __rw_entry(v, va, value, DIRECT_ENTRY | SET_ENTRY | PAGING_L2)
+#define __direct_get_l2e(v, va, sl2e) \
+  __rw_entry(v, va, sl2e, DIRECT_ENTRY | GET_ENTRY | PAGING_L2)
+#define __direct_set_l1e(v, va, value) \
+  __rw_entry(v, va, value, DIRECT_ENTRY | SET_ENTRY | PAGING_L1)
+#define __direct_get_l1e(v, va, sl1e) \
+  __rw_entry(v, va, sl1e, DIRECT_ENTRY | GET_ENTRY | PAGING_L1)
+
+
 static inline int  __guest_set_l2e(
     struct vcpu *v, unsigned long va, void *value, int size)
 {